package com.googlecode.groovyworks.grails;

import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.StrutsStatics;
import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.GrailsConfigUtils;
import org.codehaus.groovy.grails.commons.TagLibArtefactHandler;
import org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext;
import org.codehaus.groovy.grails.web.pages.GSPResult;
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes;
import org.codehaus.groovy.grails.web.servlet.GrailsUrlPathHelper;
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
import org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper;
import org.springframework.beans.BeansException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.UrlPathHelper;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.config.entities.ActionConfig;

/**
 * Invokes a Grails Controller and Result
 */
public class GrailsActionProxy implements ActionProxy, StrutsStatics {
	private GrailsWebRequest webRequest;
	private UrlPathHelper urlHelper = new GrailsUrlPathHelper();
	private ActionInvocation invocation;
	private Map extraContext;

	public GrailsActionProxy(ActionInvocation invocation, Map extraContext) {
		this.invocation = invocation;
		this.extraContext = extraContext;
	}

	public String execute() throws Exception {
		WebApplicationContext wac = getWebApplicationContext();
		ServletContext servletContext = (ServletContext) extraContext
				.get(SERVLET_CONTEXT);
		HttpServletRequest request = (HttpServletRequest) extraContext
				.get(HTTP_REQUEST);
		HttpServletResponse response = (HttpServletResponse) extraContext
				.get(HTTP_RESPONSE);
		GrailsApplication application = (GrailsApplication) wac
				.getBean("grailsApplication");
		webRequest = new GrailsWebRequest(request, response, servletContext);
		RequestContextHolder.setRequestAttributes(webRequest);
		SimpleGrailsControllerHelper helper = new SimpleGrailsControllerHelper(
				application, wac, servletContext);
		String uri = urlHelper.getPathWithinApplication(request);
		ModelAndView mv = helper.handleURI(uri, webRequest);
		String resultName = mv.getViewName();
		GSPResult gspResult = new GSPResult();
		request.setAttribute(GrailsApplicationAttributes.WEB_REQUEST, webRequest);
		RequestContextHolder.setRequestAttributes(webRequest);
		//servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appContext);
		application.registerArtefactHandler(new TagLibArtefactHandler());
		gspResult.doExecute(resultName, request, response, servletContext);
		return resultName;
	}

	protected WebApplicationContext getWebApplicationContext()
			throws BeansException {
		ServletContext servletContext = (ServletContext) extraContext
				.get(SERVLET_CONTEXT);
		WebApplicationContext wac = WebApplicationContextUtils
				.getWebApplicationContext(servletContext);

		GrailsApplication application = (GrailsApplication) wac
				.getBean("grailsApplication");

		if (wac instanceof GrailsWebApplicationContext) {
			return wac;
		} else {
			wac = GrailsConfigUtils.configureWebApplicationContext(
					servletContext, wac);
		}

		GrailsConfigUtils.executeGrailsBootstraps(application, wac,
				servletContext);
		return wac;
	}

	public Object getAction() {
		return null;
	}

	public String getActionName() {
		return null;
	}

	public ActionConfig getConfig() {
		return null;
	}

	public boolean getExecuteResult() {
		return false;
	}

	public ActionInvocation getInvocation() {
		return invocation;
	}

	public String getMethod() {
		return null;
	}

	public String getNamespace() {
		return null;
	}

	public void prepare() throws Exception {
	}

	public void setExecuteResult(boolean executeResult) {
	}

	public void setMethod(String method) {
	}
}
